package cn.jisol.ngame.network;

import cn.jisol.ngame.actions.core.NActionEnum;
import cn.jisol.ngame.client.NClient;
import cn.jisol.ngame.network.entity.JNetParam;
import com.google.protobuf.AbstractMessage;

import java.io.InputStream;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;


/**
 * JNGame 核心静态类
 */
public class JNetwork{

    //最小数据: 8 字节
    public final static Integer MINI_DATA = 8;

    //all处理类
    public final static Map<Integer, List<Method>> AllAction = new HashMap<>();


    public static void onMessage(InputStream stream, NClient client, Object ...args){
        //网络参数
        JNetParam netParam = JNetParam.decoder(stream);
        if(Objects.isNull(netParam)) return;
        //调用方法
        netParam.setArgsServer(args);
        JNetwork.invoke(netParam,client);
    }

    public static void onConnect(NClient client, Object ...args){
        JNetParam param = JNetParam.builder().hId(NActionEnum.ServerClientConnect).argsServer(args).build();
        invoke(param,client);
    }

    public static void onDisconnect(NClient client, Object ...args){
        JNetParam param = JNetParam.builder().hId(NActionEnum.ServerClientDisconnect).argsServer(args).build();
        invoke(param,client);
    }

    //调用处理类
    public static void invoke(JNetParam netParam,NClient client){

        //获取处理方法
        List<Method> actions;
        if(Objects.isNull(actions = (JNetwork.AllAction.get(netParam.getHId())))){
            System.out.println("[JNetwork]: 没找到处理Id为"+netParam.getHId()+"的方法.");
            return;
        }

        for (Method action : actions) {
            //调用方法
            try {
                //接收的参数类型
                Parameter[] parameters = action.getParameters();
                Object[] params = new Object[parameters.length];

                for (int i = 0; i < parameters.length; i++) {
                    //Protobuf消息
                    if(AbstractMessage.class.isAssignableFrom(parameters[i].getType())){
                        params[i] = parameters[i].getType().getMethod("parseFrom",netParam.getData().getClass()).invoke(parameters[i].getType(), (Object) netParam.getData());
                    }else{
                        //额外参数
                        for (int j = 0; j < netParam.getArgsServer().length; j++) {
                            Object param = netParam.getArgsServer()[j];
                            if(parameters[i].getType().isAssignableFrom(param.getClass())){
                                params[i] = param;
                                break;
                            }
                        }
                    }
                }

                //接受RPC 返回 如果有Protobuf 返回 则发送返回请求给客户端
                Object rData = action.invoke(null, params);
                if(Objects.nonNull(rData) && AbstractMessage.class.isAssignableFrom(rData.getClass())){

                    //如果是Proto 则 返回消息
                    client.invoke(netParam.getId(),0,(AbstractMessage)rData);

                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

    }

}
